#pragma once
#include "zMatrixBase.hpp"

//for f(mat)

namespace zzz{
#define CONSTANT_EXPRESSION(name,ope) \
template<typename T,class Major>\
class zFunction##name##Expression : public zMatrixBaseR<T,Major>\
{\
public:\
  explicit zFunction##name##Expression(const zMatrixBaseR<T,Major>& mat)\
  :zMatrixBaseR<T,Major>(mat.rows_,mat.cols_),Mat_(mat){}\
  const T operator()(zuint r, zuint c) const\
  {\
    CheckRange(r, c); \
    return ope(Mat_(r,c)); \
  }\
private:\
  const zMatrixBaseR<T,Major> &Mat_; \
}; \
template<typename T, class Major>\
const zFunction##name##Expression<T,Major> name(const zMatrixBaseR<T,Major> &mat)\
{\
  return zFunction##name##Expression<T,Major>(mat); \
}

CONSTANT_EXPRESSION(Sin,sin)
CONSTANT_EXPRESSION(Cos,cos)
CONSTANT_EXPRESSION(Tan,tan)
CONSTANT_EXPRESSION(Pos,+)
CONSTANT_EXPRESSION(Neg,-)

template<typename T,class Major>
const zFunctionPosExpression<T,Major> operator+(const zMatrixBaseR<T,Major> &mat)
{
  return zFunctionPosExpression<T,Major>(mat);
}

template<typename T,class Major>
const zFunctionNegExpression<T,Major> operator-(const zMatrixBaseR<T,Major> &mat)
{
  return zFunctionNegExpression<T,Major>(mat);
}

template<typename T, class Major>
T Trace(const zMatrixBaseR<T,Major> &mat)
{
  ZCHECK_EQ(mat.rows_, mat.cols_);
  T t=0;
  for (zuint i=0; i<mat.rows_; i++) t+=mat(i,i);
  return t;
}
}
